package com.sudo.api.aspect;

import com.sudo.common.utils.*;
import com.sudo.dao.admin.entity.SysUserBehavior;
import com.sudo.dao.admin.model.dto.OnlineUserDTO;
import com.sudo.starter.ip2region.pojo.IpInfo;
import com.sudo.starter.ip2region.strategy.Ip2RegionStrategy;
import com.sudo.starter.log.constant.LogConstant;
import com.sudo.service.admin.service.AdminBaseService;
import com.sudo.service.admin.service.SysRedisAuthService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

/**
 * @author 为道日损 2020-04-24 11:05
 */
@Order(3)
@Slf4j
@Aspect
@Component
public class DbLogAspect extends AdminBaseService {

    @Resource
    private Ip2RegionStrategy ip2RegionStrategy;
    @Resource
    private SysRedisAuthService sysRedisAuthService;

    private static final String[] excludeUriArr = {
            "/sysInfo/getCpuMemInfoActualTimeByServer",
            "/sysUser/generateImageCode",
            "/sysUser/postEmailCode",
            "/sysUser/userRegister"
    };

    /**
     * 定义切入点Pointcut
     * 在注解的位置切入代码
     */
    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void logPointCut() {}

    /**
     * 切面 配置通知
     */
    @Around("logPointCut()")
    public Object getDbLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Object object;
        //记录开始时间
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //从切面织入处通过反射机制获取织入点处的方法
        Method method = methodSignature.getMethod();
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = joinPoint.getSignature().getName();
        //请求参数
        Object[] args = joinPoint.getArgs();
        Map<String, Object> nameAndArgs = ParamUtil.getParamMap(method, args);
        log.info("=== 开始执行 {}.{} ===",className, methodName);


        HttpServletRequest request = HttpServletUtil.getRequest();
        String username = HttpUserInfoUtil.getSessionUser(request);
        String requestURI = request.getRequestURI();
        log.info("  请求地址：{}",requestURI);
        log.info("  请求参数：{}",nameAndArgs);

        long begin = System.currentTimeMillis();
        object = joinPoint.proceed();
        if (StringUtils.isBlank(username)) {
            log.info(">>> 提前结束，请求不携带用户 {}.{} <<<",className, methodName);
            return object;
        }
        boolean isHas = Arrays.asList(excludeUriArr).contains(requestURI);
        if (isHas) {
            log.info(">>> 提前结束，请求地址放行 {}.{} <<<",className, methodName);
            return object;
        }
        try {
            log.info("  请求用户：{}",username);
            OnlineUserDTO onlineUserDTO = sysRedisAuthService.getRedisUserToken(username);
            log.info("  请求角色：{}",onlineUserDTO.getRoleCode());
            long end = System.currentTimeMillis();

            SysUserBehavior sysUserBehavior = new SysUserBehavior();
            //获取操作
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            if (null != apiOperation) {
                String value = apiOperation.value();
                sysUserBehavior.setOperEvent(value);
            }
            sysUserBehavior.setOperMethod(className + "#" + methodName);

            nameAndArgs.remove("request");
            nameAndArgs.remove("response");
            //将参数所在的数组转换为json
            sysUserBehavior.setReqParam(nameAndArgs.toString());
            String now = LocalDateTimeUtil.getStandardDateTimeStr();
            sysUserBehavior.setOperTime(now);
            sysUserBehavior.setUsername(username);
            sysUserBehavior.setRoleCode(onlineUserDTO.getRoleCode());
            String ipAddress = IpAddressUtil.getIpAddress(request);
            String search = ip2RegionStrategy.search(ipAddress);

            if (StringUtils.isNotBlank(search)) {
                IpInfo ipInfo = new IpInfo(search);
                sysUserBehavior.setCountry(ipInfo.getCountry());
                sysUserBehavior.setProvince(ipInfo.getProvince());
                sysUserBehavior.setCity(ipInfo.getCity());
            }

            sysUserBehavior.setClientIp(ipAddress);
            sysUserBehavior.setReqUrl(request.getRequestURI());
            sysUserBehavior.setReqType(request.getMethod());
            sysUserBehavior.setTraceId(MDC.get(LogConstant.TRACE_ID));
            HttpServletResponse response = HttpServletUtil.getResponse();
            sysUserBehavior.setRespStatus(response.getStatus());
            sysUserBehavior.setUseTime(end-begin);

            // sysUserBehaviorService.addSysUserBehavior(sysUserBehavior);
            sysRedisAuthService.setRedisUserBehavior(sysUserBehavior);
            log.info("=== 结束执行 {}.{} ===",className, methodName);

        }catch (Exception e){
            log.error("DbLogAspect 异常",e);
        }
        return object;
    }


}
